package 多线程.AQS;

import java.util.concurrent.*;

/**
 * 在这个程序中，我们模拟了4个队伍参加赛龙舟比赛。每个队伍都在启动时创建一个独立的线程，
 * 并在比赛前等待1~4秒的准备时间。当所有队伍都准备就绪后，裁判发出比赛开始信号，龙舟开始前进。
 * 程序中使用Semaphore来控制龙舟数量，每次只有一个队伍可以使用龙舟。
 * 当某个队伍完成比赛后，程序会使用CyclicBarrier来等待其他队伍完成比赛，并且进行庆祝活动。
 */
public class DragonBoatRace {
    /**
     * 参赛队伍数
     */
    private static final int TEAM_NUM = 4;
    /**
     * 龙舟数量
     */
    private static final int BOAT_NUM = 1;
    private static final Semaphore semaphore = new Semaphore(BOAT_NUM);
    private static final CountDownLatch startLatch = new CountDownLatch(TEAM_NUM);
    private static final CyclicBarrier finishBarrier = new CyclicBarrier(TEAM_NUM+1);

    public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
        ExecutorService executorService = Executors.newFixedThreadPool(TEAM_NUM);
        for (int i = 0; i < TEAM_NUM; i++) {
            executorService.submit(new Team(i + 1));
        }
        // 等待所有队伍准备就绪
        startLatch.await();
        // 获取龙舟信号量
        System.out.println("龙舟已经准备好！");
        System.out.println("所有队伍准备就绪,比赛开始！");
        semaphore.acquire();
        // 等待2秒，模拟龙舟前进
        Thread.sleep(2000);
        // 释放龙舟信号量
        semaphore.release();
        // 等待所有队伍完成比赛
        //下面这个应该是不要的，没用。
        finishBarrier.await();
        System.out.println("比赛结束！");
        System.out.println("所有队伍完成比赛，开始庆祝！");
        // 关闭线程池
        executorService.shutdown();
    }

    static class Team implements Runnable {
        private final int teamId;

        public Team(int teamId) {
            this.teamId = teamId;
        }

        @Override
        public void run() {
            try {
                Thread.sleep(1000 * teamId); // 模拟队伍准备时间
                System.out.println("队伍" + teamId + "已准备就绪！");
                startLatch.countDown(); // 准备就绪，计数器减一
                semaphore.acquire(); // 获取龙舟信号量
                System.out.println("队伍" + teamId + "已上船，准备出发！");
                Thread.sleep(2000); // 等待2秒，模拟龙舟前进
                System.out.println("队伍" + teamId + "已完成比赛！");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                semaphore.release(); // 释放龙舟信号量
                try {
                    finishBarrier.await(); // 等待其他队伍完成比赛
                    System.out.println("队伍" + teamId + "正在庆祝！");
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

